#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <sys/types.h>
#include <unistd.h>
#include <fstream>
#include <iostream>

static int doReboot(int argc, char* argv[])
{
    sync();
    sync();
    sync();
    system("reboot");
    return 0;
}

static int doShutdown(int argc, char* argv[])
{
    sync();
    sync();
    sync();
    system("shutdown -h now");
    return 0;
}

static int doSetTime(int argc, char* argv[])
{
    if (argc < 3)
    {
        return -1;  // incorrect arg num
    }
    if (strlen(argv[2]) > 128)
    {
        return -2;  // too long time string
    }
    char strCmdBuf[256];
    sprintf(strCmdBuf, "timedatectl set-ntp false; date -s \'%s\' && hwclock --systohc", argv[2]);
    system(strCmdBuf);
    return 0;
}

static int doInstall(int argc, char* argv[])
{
    sync();
    sync();
    sync();
    system("make install");
    return 0;
}

static int doSshStart(int argc, char* argv[])
{
    system("service ssh start");
    return 0;
}

static int doSshStop(int argc, char* argv[])
{
    system("service ssh stop");
    system("pkill -9 sshd");
    return 0;
}

static int setsshclientip(int argc, char* argv[])
{
    std::string ip = argv[2];
    std::ofstream hostsAllowFile;
    hostsAllowFile.open("/etc/hosts.allow");
    if (!hostsAllowFile.is_open())
    {
        std::cerr << "Error:Cannot open config file" << std::endl;
        return 1;
    }
    hostsAllowFile << "sshd:" << ip << ":allow" << std::endl;
    hostsAllowFile.close();
    return 0;
}

static int disService(int argc, char* argv[])
{
    if (!strcmp(argv[2], "jkbrd"))
    {
        system("systemctl disable jkbrd");
        return 0;
    }
    return -1;
}

static int stopService(int argc, char* argv[])
{
    if (!strcmp(argv[2], "jkbrd"))
    {
        system("systemctl stop jkbrd");
        return 0;
    }
    return -1;
}

static int restartService(int argc, char* argv[])
{
    if (!strcmp(argv[2], "systemd-networkd"))
    {
        system("systemctl restart systemd-networkd");
    }
    if (!strcmp(argv[2], "jkzuc"))
    {
        system("systemctl restart jkzuc");
    }
    return 0;
}

static uint32_t getNum(const char* argv, uint32_t defaultVal)
{
    uint32_t ret = 0;
    try
    {
        ret = std::stoul(argv);
    }
    catch (...)
    {
        ret = 0;
    }

    if (!ret)
    {
        ret = defaultVal;
    }
    return ret;
}

static int dumpLogFile(int argc, char* argv[])
{
    uint32_t hours;
    uint32_t readlines;

    if (argc < 4)
    {
        hours = 4;
        readlines = 5000;
    }
    else
    {
        hours = getNum(argv[2], 4);
        readlines = getNum(argv[3], 5000);
    }

    std::string cmd = "journalctl --since \"" + std::to_string(hours) + " hour ago\" -n " + std::to_string(readlines);
    if (system(cmd.c_str()) != 0)
    {
        std::cerr << "journalctl: " << strerror(errno) << "\n";
    }

    return 0;
}

static int ecatInit(int argc, char* argv[])
{
    if (!strcmp(argv[2], "restart"))
    {
        system("/etc/init.d/ethercat restart");
    }
    if (!strcmp(argv[2], "stop"))
    {
        system("/etc/init.d/ethercat stop");
    }
    return 0;
}

/* the following commands are supported to be executed:
	shutils reboot				               -- /sbin/reboot
	shutils shutdown			               -- /sbin/shutdown -h now
	shutils settime timestring                 -- date -s \"%s\" && /sbin/hwclock --systohc
	shutils install				               -- make install	
	shutils sshstart			               -- start sshserver
	shutils sshstop				               -- stop sshserver & kill established connect
    shutils setsshclientip [ip]	               -- set ip accessable to ssh server
    shutils restartService  service_name       -- "systemctl restart \'%s\'"
    shutils disService  service_name           -- "systemctl disable \'%s\'"
    shutils stopService  service_name          -- "systemctl stop \'%s\'"
    shutils ecat restart/stop                  -- "/etc/init.d/ethercat \'%s\'"
*/
int main(int argc, char* argv[])
{
    int ret = -1;
    if ((setuid(0)) != 0)
    {  // switch to root
        perror("error switch to super user");
    }
    else
    {
        const char* currPath = getenv("PATH");
        // printf("PATH: %s\n", currPath);
        std::string newPath = std::string(currPath) + ":/sbin:/usr/sbin:/usr/local/sbin";
        setenv("PATH", newPath.c_str(), 1);
        // printf("PATH: %s\n", getenv("PATH"));
    }

    if (!strcmp(argv[1], "reboot"))
    {
        ret = doReboot(argc, argv);
    }
    else if (!strcmp(argv[1], "shutdown"))
    {
        ret = doShutdown(argc, argv);
    }
    else if (!strcmp(argv[1], "settime"))
    {
        ret = doSetTime(argc, argv);
    }
    else if (!strcmp(argv[1], "install"))
    {
        ret = doInstall(argc, argv);
    }
    else if (!strcmp(argv[1], "sshstart"))
    {
        ret = doSshStart(argc, argv);
    }
    else if (!strcmp(argv[1], "sshstop"))
    {
        ret = doSshStop(argc, argv);
    }
    else if (!strcmp(argv[1], "disService"))
    {
        ret = disService(argc, argv);
    }
    else if (!strcmp(argv[1], "stopService"))
    {
        ret = stopService(argc, argv);
    }
    else if (!strcmp(argv[1], "setsshclientip"))
    {
        ret = setsshclientip(argc, argv);
    }
    else if (!strcmp(argv[1], "restartService"))
    {
        ret = restartService(argc, argv);
    }
    else if (!strcmp(argv[1], "dumpLog"))
    {
        ret = dumpLogFile(argc, argv);
    }
    else if (!strcmp(argv[1], "ecat"))
    {
        ret = ecatInit(argc, argv);
    }

    if (ret != 0)
    {
        printf("Failed to exec cmd, arg count: %d\n", argc);
        for (int i = 0; i < argc; i++) { printf("arg %d: %s\n", i, argv[i]); }
        perror("failed to execute the command");
    }

    return ret;
}
